﻿#include "qt_renderer.h"
#include "MainOpenGLWidget.h"
#include "ais/ais_box.h"
#include "ais/ais_camera.h"
#include "ais/ais_curve.h"
#include "ais/ais_frame.h"
#include "ais/ais_light.h"
#include "ais/ais_mesh.h"
#include "ais/ais_point.h"
#include "ais/ais_pointcloud.h"
#include "ais/ais_pole.h"
#include "ais/ais_surface.h"
#include "ais/ais_vector.h"
#include "ais/ais_vectorcloud.h"
#include "kernel/transform.h"

// 引入字符纹理库
#include <ft2build.h>
#include FT_FREETYPE_H

using namespace CAGD;

/**
 * 保存字形纹理信息.
 */
struct Character
{
    unsigned int ID;      // 字形纹理的ID
    unsigned int advance; // 原点距下一个字形原点的距离
    Size size;            // 字形大小
    Point bearing;        // 从基准线到字形左部/顶部的偏移值
};

/**
 * 保存字形高度.
 */
int g_height = 0;

/**
 * 保存对应关系.
 */
std::map<char, Character> g_characters;

/**
 * @brief 初始化纹理.
 * @return
 * @param parent
 * @param height
 * @see
 */
bool init_text_textures(MainOpenGLWidget *parent, int height)
{
    // 保存字形高度
    g_height = height;

    // 一定要进入环境
    parent->makeCurrent();

    // 初始化字符纹理
    FT_Library ft;
    if (FT_Init_FreeType(&ft))
        qDebug() << "ERROR::FREETYPE: Could not init FreeType Library";

    FT_Face face;
    std::string path = CAGD_RC_PATH + std::string("/fonts/consola.ttf");
    if (FT_New_Face(ft, path.c_str(), 0, &face))
        qDebug() << "ERROR::FREETYPE: Failed to load font";

    // 指定字体大小，宽度为 0，表示根据高度计算宽度
    FT_Set_Pixel_Sizes(face, 0, height);

    // 由于产生的纹理只有一个字节，禁用字节对齐限制
    parent->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    for (GLubyte c = 0; c < 128; c++)
    {
        // 加载字符的字形
        if (FT_Load_Char(face, c, FT_LOAD_RENDER))
        {
            std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
            return false;
        }

        // 生成纹理
        GLuint texture;
        parent->glGenTextures(1, &texture);
        parent->glBindTexture(GL_TEXTURE_2D, texture);
        parent->glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_RED,
                             GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer);

        // 设置纹理选项
        parent->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        parent->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        parent->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        parent->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // 储存字符供之后使用
        Character character = {texture, face->glyph->advance.x,
                               Size{face->glyph->bitmap.width, face->glyph->bitmap.rows},
                               Point{face->glyph->bitmap_left, face->glyph->bitmap_top}};

        g_characters.insert(std::pair<char, Character>(c, character));
    }

    // 恢复
    parent->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

    // 清理资源
    FT_Done_Face(face);
    FT_Done_FreeType(ft);

    // 退出环境
    parent->doneCurrent();

    return true;
}

/**
 * @brief 销毁字符纹理.
 * @param parent
 * @see
 */
void destroy_text_textures(MainOpenGLWidget *parent)
{
    // 进入环境
    parent->makeCurrent();

    for (auto &it : g_characters)
        parent->glDeleteTextures(1, &it.second.ID);

    // 退出环境
    parent->doneCurrent();
}

#define PI 3.1415926535
#define RAD(a) (a) / 180.0 * PI

#define CONVERT_TO_QVEC_3(vec)                                                                                         \
    QVector3D                                                                                                          \
    {                                                                                                                  \
        vec.X(), vec.Y(), vec.Z()                                                                                      \
    }

#define CONVERT_TO_QVEC_4(vec)                                                                                         \
    QVector4D                                                                                                          \
    {                                                                                                                  \
        vec.X(), vec.Y(), vec.Z(), 1                                                                                   \
    }

#define CONVERT_TO_QMAT_4(mat)                                                                                         \
    QMatrix4x4                                                                                                         \
    {                                                                                                                  \
        mat(0, 0), mat(0, 1), mat(0, 2), mat(0, 3), mat(1, 0), mat(1, 1), mat(1, 2), mat(1, 3), mat(2, 0), mat(2, 1),  \
            mat(2, 2), mat(2, 3), mat(3, 0), mat(3, 1), mat(3, 2), mat(3, 3),                                          \
    }

CAGD::RendererExt::RendererExt(MainOpenGLWidget *parent) : Renderer(parent)
{
}

CAGD::RendererExt::~RendererExt()
{
    // 销毁数组
    m_parent->DeleteArray(m_arrayId);
}

CAGD::RendererPoint::RendererPoint(MainOpenGLWidget *parent) : RendererExt(parent)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 创建着色器
    m_parent->GenerateShader(AIS_Type::POINT, ":/shader/cloud.vert", ":/shader/cloud.frag");
    m_parent->GenerateArray(m_arrayId);

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererPoint::UpdateUniform(AIS_Base *obj)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 获得信息
    auto &info = obj->GetInfo();

    m_parent->BindShader(AIS_Type::POINT);

    // 获得观察位置和变换矩阵
    auto pos = m_context.GetInfo().viewPos;
    auto model = CONVERT_TO_QMAT_4(info.modelMat);
    auto view = CONVERT_TO_QMAT_4(m_context.GetInfo().viewMat);
    auto projection = CONVERT_TO_QMAT_4(m_context.GetInfo().projectionMat);

    m_parent->GetShader()->setUniformValue("model", model);
    m_parent->GetShader()->setUniformValue("view", view);
    m_parent->GetShader()->setUniformValue("projection", projection);
    m_parent->GetShader()->setUniformValue("viewPos", CONVERT_TO_QVEC_3(pos));
    m_parent->GetShader()->setUniformValue("color", CONVERT_TO_QVEC_4(info.color));

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererPoint::Draw(AIS_Base *obj) const
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 获得信息
    auto &info = obj->GetInfo();

    m_parent->BindShader(AIS_Type::POINT);

    // 配置绘制信息，允许后绘制的内容覆盖之前的内容
    m_parent->glPointSize(info.psize);
    m_parent->glDepthFunc(GL_LEQUAL);

    if (info.smooth)
        m_parent->glEnable(GL_POINT_SMOOTH);

    // 开始绘制
    m_parent->BindArray(m_arrayId);
    m_parent->glDrawArrays(GL_POINTS, 0, info.size);

    m_parent->UnbindArray();

    // 恢复默认
    m_parent->glPointSize(1);
    m_parent->glDepthFunc(GL_LESS);
    m_parent->glDisable(GL_POINT_SMOOTH);

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::RendererVector::RendererVector(MainOpenGLWidget *parent) : RendererExt(parent)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 创建着色器
    m_parent->GenerateShader(AIS_Type::VECTOR, ":/shader/vector.vert", ":/shader/vector.frag", ":/shader/vector.geom");
    m_parent->GenerateArray(m_arrayId);

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererVector::UpdateUniform(AIS_Base *obj)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 获得信息
    auto &info = obj->GetInfo();

    // 绘制物体
    m_parent->BindShader(AIS_Type::VECTOR);

    // 获得观察位置和变换矩阵
    auto pos = m_context.GetInfo().viewPos;
    auto model = CONVERT_TO_QMAT_4(info.modelMat);
    auto view = CONVERT_TO_QMAT_4(m_context.GetInfo().viewMat);
    auto projection = CONVERT_TO_QMAT_4(m_context.GetInfo().projectionMat);

    m_parent->GetShader()->setUniformValue("model", model);
    m_parent->GetShader()->setUniformValue("view", view);
    m_parent->GetShader()->setUniformValue("projection", projection);
    m_parent->GetShader()->setUniformValue("viewPos", CONVERT_TO_QVEC_3(pos));
    m_parent->GetShader()->setUniformValue("color", CONVERT_TO_QVEC_4(info.color));

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererVector::Draw(AIS_Base *obj) const
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 绘制物体
    m_parent->BindShader(AIS_Type::VECTOR);

    // 关闭深度缓冲，防止抗锯齿产生缝隙
    // m_parent->glEnable(GL_POLYGON_SMOOTH);
    // m_parent->glDepthMask(GL_FALSE);
    // m_parent->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    // 开始绘制
    m_parent->BindArray(m_arrayId);
    m_parent->glDrawArrays(GL_POINTS, 0, 1);

    // m_parent->glDisable(GL_POLYGON_SMOOTH);
    //  m_parent->glDepthMask(GL_TRUE);

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::RendererNormal::RendererNormal(MainOpenGLWidget *parent) : RendererExt(parent)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 创建着色器
    m_parent->GenerateShader(AIS_Type::VECTORCLOUD, ":/shader/normal.vert", ":/shader/normal.frag",
                             ":/shader/normal.geom");
    m_parent->GenerateArray(m_arrayId);

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererNormal::UpdateUniform(AIS_Base *obj)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 获得信息
    auto &info = obj->GetInfo();

    m_parent->BindShader(AIS_Type::VECTORCLOUD);

    // 获得观察位置和变换矩阵
    auto pos = m_context.GetInfo().viewPos;
    auto model = CONVERT_TO_QMAT_4(info.modelMat);
    auto view = CONVERT_TO_QMAT_4(m_context.GetInfo().viewMat);
    auto projection = CONVERT_TO_QMAT_4(m_context.GetInfo().projectionMat);

    m_parent->GetShader()->setUniformValue("model", model);
    m_parent->GetShader()->setUniformValue("view", view);
    m_parent->GetShader()->setUniformValue("projection", projection);
    m_parent->GetShader()->setUniformValue("viewPos", CONVERT_TO_QVEC_3(pos));
    m_parent->GetShader()->setUniformValue("color", CONVERT_TO_QVEC_4(info.color));

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererNormal::Draw(AIS_Base *obj) const
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 获得信息
    auto &info = obj->GetInfo();

    m_parent->BindShader(AIS_Type::VECTORCLOUD);

    // 设置线粗
    m_parent->glLineWidth(m_context.GetInfo().linewidth);

    // 开始绘制
    m_parent->BindArray(m_arrayId);
    m_parent->glDrawArrays(GL_POINTS, 0, info.size);

    // 还原线宽
    m_parent->glLineWidth(1);

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::RendererCurve::RendererCurve(MainOpenGLWidget *parent) : RendererExt(parent)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 创建着色器
    m_parent->GenerateShader(AIS_Type::CURVE, ":/shader/curve.vert", ":/shader/curve.frag");
    m_parent->GenerateArray(m_arrayId);

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererCurve::UpdateUniform(AIS_Base *obj)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 获得信息
    auto &info = obj->GetInfo();

    m_parent->BindShader(AIS_Type::CURVE);

    // 获得观察位置和变换矩阵
    auto pos = m_context.GetInfo().viewPos;
    auto model = CONVERT_TO_QMAT_4(info.modelMat);
    auto view = CONVERT_TO_QMAT_4(m_context.GetInfo().viewMat);
    auto projection = CONVERT_TO_QMAT_4(m_context.GetInfo().projectionMat);

    m_parent->GetShader()->setUniformValue("model", model);
    m_parent->GetShader()->setUniformValue("view", view);
    m_parent->GetShader()->setUniformValue("projection", projection);
    m_parent->GetShader()->setUniformValue("viewPos", CONVERT_TO_QVEC_3(pos));

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererCurve::Draw(AIS_Base *obj) const
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 获得信息
    auto &info = obj->GetInfo();

    m_parent->BindShader(AIS_Type::CURVE);

    int enableTex = info.diffuseTex == 0 ? 0 : 1;
    m_parent->GetShader()->setUniformValue("enableTex", enableTex);
    if (enableTex)
    {
        m_parent->ActiveTexture(0);
        m_parent->BindTexture1D(info.diffuseTex);
        m_parent->GetShader()->setUniformValue("tex", 0);
    }
    else
        m_parent->GetShader()->setUniformValue("color", CONVERT_TO_QVEC_4(info.color));

    // 修改线宽
    m_parent->glLineWidth(m_context.GetInfo().linewidth);
    if (info.smooth)
        m_parent->glEnable(GL_LINE_SMOOTH);

    // 开始绘制
    m_parent->BindArray(m_arrayId);
    m_parent->glDrawArrays(GL_LINE_STRIP, 0, info.size);

    // 还原线宽
    m_parent->glLineWidth(1);
    m_parent->glDisable(GL_LINE_SMOOTH);

    m_parent->UnbindArray();
    m_parent->UnbindTexture();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::RendererMesh::RendererMesh(MainOpenGLWidget *parent) : RendererExt(parent)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 创建着色器
    m_parent->GenerateShader(AIS_Type::MESH, ":/shader/mesh.vert", ":/shader/mesh.frag", ":/shader/mesh.geom");
    m_parent->GenerateArray(m_arrayId);

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererMesh::UpdateUniform(AIS_Base *obj)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 绘制网格
    m_parent->BindShader(AIS_Type::MESH);

    // 获得观察位置和变换矩阵
    auto pos = m_context.GetInfo().viewPos;
    auto model = CONVERT_TO_QMAT_4(obj->GetInfo().modelMat);
    auto view = CONVERT_TO_QMAT_4(m_context.GetInfo().viewMat);
    auto projection = CONVERT_TO_QMAT_4(m_context.GetInfo().projectionMat);

    m_parent->GetShader()->setUniformValue("model", model);
    m_parent->GetShader()->setUniformValue("view", view);
    m_parent->GetShader()->setUniformValue("projection", projection);
    m_parent->GetShader()->setUniformValue("viewPos", CONVERT_TO_QVEC_3(pos));

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererMesh::Draw(AIS_Base *obj) const
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 绘制网格
    m_parent->BindShader(AIS_Type::MESH);

    GLenum mode = m_context.GetInfo().shadeMode == ShadeMode::FILL ? GL_FILL : GL_LINE;
    m_parent->glPolygonMode(GL_FRONT_AND_BACK, mode);

    // 清除模板缓冲，允许所有模板通过，允许写入缓冲
    m_parent->glClear(GL_STENCIL_BUFFER_BIT);
    m_parent->glStencilFunc(GL_ALWAYS, 1, 0xFF);
    m_parent->glStencilMask(0xFF);

    m_parent->ActiveTexture(0);
    m_parent->BindTexture2D(obj->GetInfo().diffuseTex);
    m_parent->GetShader()->setUniformValue("material.duffuse", 0);

    m_parent->ActiveTexture(1);
    m_parent->BindTexture2D(obj->GetInfo().specularTex);
    m_parent->GetShader()->setUniformValue("material.specular", 1);

    m_parent->ActiveTexture(2);
    m_parent->BindTexture2D(obj->GetInfo().reflectTex);
    m_parent->GetShader()->setUniformValue("material.reflect_", 2);

    m_parent->ActiveTexture(3);
    m_parent->BindTexture2D(obj->GetInfo().reflactTex);
    m_parent->GetShader()->setUniformValue("material.reflact", 3);

    // 设置斑马纹
    int zebra = m_context.GetInfo().zebra;
    m_parent->GetShader()->setUniformValue("zebra", zebra);

    unsigned int skybox = m_context.GetInfo().skyboxTex;
    if (skybox)
    {
        m_parent->ActiveTexture(4);
        m_parent->BindTextureCube(skybox);
        m_parent->GetShader()->setUniformValue("skybox", 4);
    }

    // 开始绘制
    m_parent->BindArray(m_arrayId);

    // 如果处于触碰状态，绘制一个大一圈的结果
    m_parent->glDrawElementsInstanced(GL_TRIANGLES, obj->GetInfo().size, GL_UNSIGNED_INT, 0,
                                      obj->GetInfo().insMats.size());

    if (obj->GetInfo().status != AIS_Status::NONE)
    {
        auto model = obj->GetInfo().modelMat * Transform::Scale(obj->GetInfo().centroid, {1.05, 1.05, 1.05});
        m_parent->GetShader()->setUniformValue("model", CONVERT_TO_QMAT_4(model));

        // 只允许不为 1 的模板通过
        m_parent->glStencilFunc(GL_NOTEQUAL, 1, 0xFF);

        m_parent->ActiveTexture(0);
        m_parent->BindTexture2D(TEXTURE::BLUE2D);
        m_parent->GetShader()->setUniformValue("material.duffuse", 0);

        m_parent->glDrawElementsInstanced(GL_TRIANGLES, obj->GetInfo().size, GL_UNSIGNED_INT, 0,
                                          obj->GetInfo().insMats.size());

        // 恢复初始设置
        m_parent->glStencilMask(0xFF);
        m_parent->glStencilFunc(GL_ALWAYS, 1, 0xFF);
    }

    m_parent->UnbindArray();
    m_parent->UnbindTexture();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::RendererFrame::RendererFrame(MainOpenGLWidget *parent) : RendererExt(parent)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 创建着色器
    m_parent->GenerateShader(AIS_Type::FRAME, ":/shader/frame.vert", ":/shader/frame.frag");
    m_parent->GenerateArray(m_arrayId);

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererFrame::UpdateArray(AIS_Base *obj)
{
    // 注意不要使用静态本地变量来控制创建 frame，因为它是全局的，没有用

    auto f = dynamic_cast<AIS_Frame *>(obj);
    auto fpos = f->GetPosition();
    auto fsize = f->GetSize();
    auto gsize = m_context.GetInfo().size;

    BPnt2df pos = {2.0f * fpos.x / gsize.x - 1.0f, 2.0f * (gsize.y - (fpos.y + fsize.y)) / gsize.y - 1.0f};
    BPnt2df size = BPnt2df{2.0f * fsize.x / gsize.x, 2.0f * fsize.y / gsize.y};

    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->GenerateFrame(m_arrayId, fsize.x, fsize.y);
    m_parent->BindArray(m_arrayId);

    float vertices[6][4] = {{pos.X(), pos.Y(), 0.0f, 0.0f},
                            {pos.X() + size.X(), pos.Y(), 1.0f, 0.0f},
                            {pos.X() + size.X(), pos.Y() + size.Y(), 1.0f, 1.0f},
                            {pos.X(), pos.Y(), 0.0f, 0.0f},
                            {pos.X(), pos.Y() + size.Y(), 0.0f, 1.0f},
                            {pos.X() + size.X(), pos.Y() + size.Y(), 1.0f, 1.0f}};

    m_parent->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_STATIC_DRAW);

    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void *)0);

    m_parent->glEnableVertexAttribArray(1);
    m_parent->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void *)(2 * sizeof(float)));

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::RendererFrame::UpdateUniform(AIS_Base *obj)
{
    // 什么都不做
}

void CAGD::RendererFrame::Prepare(AIS_Base *obj) const
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    auto &info = obj->GetInfo();

    // 绑定帧缓冲
    m_parent->BindFrame(m_arrayId);
    m_parent->glClearColor(info.color.X(), info.color.Y(), info.color.Z(), info.color.W());
    m_parent->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

void CAGD::RendererFrame::Done(AIS_Base *obj) const
{
    // 结束绘制
    m_parent->UnbindFrame();

    // 绘制帧缓冲
    m_parent->BindShader(AIS_Type::FRAME);
    m_parent->glDisable(GL_DEPTH_TEST);
    m_parent->BindArray(m_arrayId);

    // 激活纹理，绑定到帧缓冲附加的纹理，绑定纹理坐标到纹理变量
    m_parent->ActiveTexture(0);
    m_parent->glBindTexture(GL_TEXTURE_2D, m_parent->m_frames[m_arrayId].textureID);
    m_parent->GetShader()->setUniformValue("tex", 0);
    m_parent->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    m_parent->glDrawArrays(GL_TRIANGLES, 0, 6);

    m_parent->UnbindTexture();
    m_parent->UnbindArray();

    m_parent->glEnable(GL_DEPTH_TEST);

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

//////////////////////////////////////////////////////////////////////////////////////////
///
///

CAGD::ShdPoint::ShdPoint(MainOpenGLWidget *parent) : RendererPoint(parent)
{
}

void CAGD::ShdPoint::UpdateArray(AIS_Base *obj)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 获得点云
    AIS_Point *p = dynamic_cast<AIS_Point *>(obj);
    BPntf pos = p->GetPoint()->Point();

    m_parent->glBufferData(GL_ARRAY_BUFFER, sizeof(BPntf), &pos, GL_DYNAMIC_DRAW);

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdPointCloud::ShdPointCloud(MainOpenGLWidget *parent) : RendererPoint(parent)
{
}

void CAGD::ShdPointCloud::UpdateArray(AIS_Base *obj)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 获得点云
    AIS_PointCloud *p = dynamic_cast<AIS_PointCloud *>(obj);

    // 注意转换为 float
    auto &tposs = p->GetPoints();
    std::vector<BPntf> poss;
    for (auto &p : tposs)
        poss.push_back(p);
    int size = poss.size();

    m_parent->glBufferData(GL_ARRAY_BUFFER, size * sizeof(BPntf), &poss[0], GL_DYNAMIC_DRAW);

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdVector::ShdVector(MainOpenGLWidget *parent) : RendererVector(parent)
{
}

void CAGD::ShdVector::UpdateArray(AIS_Base *obj)
{
    // 获得信息
    auto info = obj->GetInfo();

    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 获得点云
    AIS_Vector *v = dynamic_cast<AIS_Vector *>(obj);
    BPntf origin = v->GetOrigin()->Point();
    BVecf vec = v->GetVector()->Vector();

    // 创建空的缓冲
    m_parent->glBufferData(GL_ARRAY_BUFFER, 2 * sizeof(BPntf), NULL, GL_DYNAMIC_DRAW);

    // 分批填充
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(BPntf), &origin);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, sizeof(BPntf), sizeof(BPntf), &vec);

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    // vertex texture coords
    m_parent->glEnableVertexAttribArray(1);
    m_parent->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)(sizeof(BPntf)));

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdVectorCloud::ShdVectorCloud(MainOpenGLWidget *parent) : RendererNormal(parent)
{
}

void CAGD::ShdVectorCloud::UpdateArray(AIS_Base *obj)
{
    // 获得信息
    auto info = obj->GetInfo();

    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 获得点云
    auto &tos = dynamic_cast<AIS_VectorCloud *>(obj)->GetOrigins();
    auto &tns = dynamic_cast<AIS_VectorCloud *>(obj)->GetVectors();

    // 转换为 float
    std::vector<BPntf> os;
    for (auto &p : tos)
        os.push_back(p);

    // 规范化
    std::vector<BVecf> ns;
    for (auto &p : tns)
        ns.push_back(p.Normalized() * 10);

    // 创建空的缓冲
    int n = info.size;
    m_parent->glBufferData(GL_ARRAY_BUFFER, 2 * n * sizeof(BPntf), NULL, GL_DYNAMIC_DRAW);

    // 分批填充
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 0, n * sizeof(BPntf), &os[0]);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, n * sizeof(BPntf), n * sizeof(BPntf), &ns[0]);

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    // vertex texture coords
    m_parent->glEnableVertexAttribArray(1);
    m_parent->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)(n * sizeof(BPntf)));

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdBox::ShdBox(MainOpenGLWidget *parent) : RendererCurve(parent)
{
}

void CAGD::ShdBox::UpdateArray(AIS_Base *obj)
{
    auto points = dynamic_cast<AIS_Box *>(obj)->GetPoints();

    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 创建纹理坐标
    int n = points.size();
    float *texCoords = new float[n];
    for (int i = 0; i < n; i++)
        texCoords[i] = 1.0 * i / (n - 1);

    // 创建空的缓冲
    m_parent->glBufferData(GL_ARRAY_BUFFER, n * (sizeof(BPntf) + sizeof(float)), NULL, GL_DYNAMIC_DRAW);

    // 分批填充
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 0, n * sizeof(BPntf), &points[0]);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, n * sizeof(BPntf), n * sizeof(float), texCoords);

    // 销毁纹理
    delete[] texCoords;

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    // vertex texture coords
    m_parent->glEnableVertexAttribArray(1);
    m_parent->glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(float), (void *)(n * sizeof(BPntf)));

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdCurve::ShdCurve(MainOpenGLWidget *parent) : RendererCurve(parent)
{
}

void CAGD::ShdCurve::UpdateArray(AIS_Base *obj)
{
    // 获得信息
    auto info = obj->GetInfo();

    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 获得曲线
    auto curve = dynamic_cast<AIS_Curve *>(obj)->GetCurve();
    auto tposs = GeomCurve::UniformPointSample(curve, info.size);

    // 注意转换为 float
    std::vector<BPntf> points;
    for (auto &p : tposs)
        points.push_back(p);

    // 创建纹理坐标
    int n = info.size;
    float *texCoords = new float[n];
    for (int i = 0; i < n; i++)
        texCoords[i] = 1.0 * i / (n - 1);

    // 创建空的缓冲
    m_parent->glBufferData(GL_ARRAY_BUFFER, n * (sizeof(BPntf) + sizeof(float)), NULL, GL_DYNAMIC_DRAW);

    // 分批填充
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 0, n * sizeof(BPntf), &points[0]);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, n * sizeof(BPntf), n * sizeof(float), texCoords);

    // 销毁纹理
    delete[] texCoords;

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    // vertex texture coords
    m_parent->glEnableVertexAttribArray(1);
    m_parent->glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(float), (void *)(n * sizeof(BPntf)));

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdMesh::ShdMesh(MainOpenGLWidget *parent) : RendererMesh(parent)
{
}

void CAGD::ShdMesh::UpdateArray(AIS_Base *obj)
{
    // 获得网格
    auto mesh = dynamic_cast<AIS_Mesh *>(obj)->GetMesh();

    // 转换数据类型
    int n = mesh->vertices.size();
    std::vector<unsigned int> indices;

    for (int i = 0; i < mesh->triangles.size(); i++)
    {
        indices.push_back(mesh->triangles[i].i);
        indices.push_back(mesh->triangles[i].j);
        indices.push_back(mesh->triangles[i].k);
    }

    // 初始化数据
    int amount = obj->GetInfo().insMats.size();
    int size = indices.size();

    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 创建空的缓冲
    m_parent->glBufferData(GL_ARRAY_BUFFER, n * (sizeof(BPntf) * 2 + sizeof(BPnt2df)), NULL, GL_DYNAMIC_DRAW);
    m_parent->glBufferData(GL_ELEMENT_ARRAY_BUFFER, size * sizeof(unsigned int), &indices[0], GL_DYNAMIC_DRAW);

    // 载入顶点和索引数据
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 0, n * sizeof(BPntf), &mesh->vertices[0]);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, n * sizeof(BPntf), n * sizeof(BPntf), &mesh->normals[0]);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 2 * n * sizeof(BPntf), n * sizeof(BPnt2df), &mesh->texcoords[0]);

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    // vertex normals
    m_parent->glEnableVertexAttribArray(1);
    m_parent->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)(n * sizeof(BPntf)));

    // vertex texture coords
    m_parent->glEnableVertexAttribArray(2);
    m_parent->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(BPnt2df), (void *)(2 * n * sizeof(BPntf)));
    // offsetof 计算变量偏移地址

    // 绑定实例数组
    m_parent->BindInsArray(m_arrayId);

    // 载入实例矩阵
    m_parent->glBufferData(GL_ARRAY_BUFFER, amount * sizeof(BMat4x4), &obj->GetInfo().insMats[0], GL_STATIC_DRAW);

    // 顶点属性允许的最大数据为 vec4，注意 QMatrix4x4 的数据规模是 68，多出 4 个字节
    int fsize = sizeof(float);
    m_parent->glEnableVertexAttribArray(3);
    m_parent->glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)0);

    m_parent->glEnableVertexAttribArray(4);
    m_parent->glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(4 * fsize));

    m_parent->glEnableVertexAttribArray(5);
    m_parent->glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(8 * fsize));

    m_parent->glEnableVertexAttribArray(6);
    m_parent->glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(12 * fsize));

    // 指定 3 4 5 6 号属性每渲染 1 个实例就更新数据
    m_parent->glVertexAttribDivisor(3, 1);
    m_parent->glVertexAttribDivisor(4, 1);
    m_parent->glVertexAttribDivisor(5, 1);
    m_parent->glVertexAttribDivisor(6, 1);

    // 载入修复矩阵
    m_parent->glBufferData(GL_ARRAY_BUFFER, amount * sizeof(BMat4x4), &obj->GetInfo().fixMats[0], GL_STATIC_DRAW);

    m_parent->glEnableVertexAttribArray(7);
    m_parent->glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)0);

    m_parent->glEnableVertexAttribArray(8);
    m_parent->glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(4 * fsize));

    m_parent->glEnableVertexAttribArray(9);
    m_parent->glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(8 * fsize));

    m_parent->glEnableVertexAttribArray(10);
    m_parent->glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(12 * fsize));

    // 指定 7 8 9 10 号属性每渲染 1 个实例就更新数据
    m_parent->glVertexAttribDivisor(7, 1);
    m_parent->glVertexAttribDivisor(8, 1);
    m_parent->glVertexAttribDivisor(9, 1);
    m_parent->glVertexAttribDivisor(10, 1);

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdSurface::ShdSurface(MainOpenGLWidget *parent) : RendererMesh(parent)
{
}

void CAGD::ShdSurface::UpdateArray(AIS_Base *obj)
{
    // 获得网格
    auto mesh = dynamic_cast<AIS_Surface *>(obj)->GetMesh();

    // 转换数据类型
    int n = mesh->vertices.size();
    std::vector<unsigned int> indices;
    std::vector<BPnt2df> texcoords(mesh->vertices.size());

    for (int i = 0; i < mesh->triangles.size(); i++)
    {
        indices.push_back(mesh->triangles[i].i);
        indices.push_back(mesh->triangles[i].j);
        indices.push_back(mesh->triangles[i].k);
    }

    // 初始化数据
    int amount = obj->GetInfo().insMats.size();
    int size = indices.size();

    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 创建空的缓冲
    m_parent->glBufferData(GL_ARRAY_BUFFER, n * (sizeof(BPntf) * 2 + sizeof(BPnt2df)), NULL, GL_DYNAMIC_DRAW);
    m_parent->glBufferData(GL_ELEMENT_ARRAY_BUFFER, size * sizeof(unsigned int), &indices[0], GL_DYNAMIC_DRAW);

    // 载入顶点和索引数据
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 0, n * sizeof(BPntf), &mesh->vertices[0]);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, n * sizeof(BPntf), n * sizeof(BPntf), &mesh->normals[0]);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 2 * n * sizeof(BPntf), n * sizeof(BPnt2df), &texcoords[0]);

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    // vertex normals
    m_parent->glEnableVertexAttribArray(1);
    m_parent->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)(n * sizeof(BPntf)));

    // vertex texture coords
    m_parent->glEnableVertexAttribArray(2);
    m_parent->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(BPnt2df), (void *)(2 * n * sizeof(BPntf)));
    // offsetof 计算变量偏移地址

    // 绑定实例数组
    m_parent->BindInsArray(m_arrayId);

    // 载入实例矩阵
    m_parent->glBufferData(GL_ARRAY_BUFFER, amount * sizeof(BMat4x4), &obj->GetInfo().insMats[0], GL_STATIC_DRAW);

    // 顶点属性允许的最大数据为 vec4，注意 QMatrix4x4 的数据规模是 68，多出 4 个字节
    int fsize = sizeof(float);
    m_parent->glEnableVertexAttribArray(3);
    m_parent->glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)0);

    m_parent->glEnableVertexAttribArray(4);
    m_parent->glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(4 * fsize));

    m_parent->glEnableVertexAttribArray(5);
    m_parent->glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(8 * fsize));

    m_parent->glEnableVertexAttribArray(6);
    m_parent->glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(12 * fsize));

    // 指定 3 4 5 6 号属性每渲染 1 个实例就更新数据
    m_parent->glVertexAttribDivisor(3, 1);
    m_parent->glVertexAttribDivisor(4, 1);
    m_parent->glVertexAttribDivisor(5, 1);
    m_parent->glVertexAttribDivisor(6, 1);

    // 载入修复矩阵
    m_parent->glBufferData(GL_ARRAY_BUFFER, amount * sizeof(BMat4x4), &obj->GetInfo().fixMats[0], GL_STATIC_DRAW);

    m_parent->glEnableVertexAttribArray(7);
    m_parent->glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)0);

    m_parent->glEnableVertexAttribArray(8);
    m_parent->glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(4 * fsize));

    m_parent->glEnableVertexAttribArray(9);
    m_parent->glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(8 * fsize));

    m_parent->glEnableVertexAttribArray(10);
    m_parent->glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, sizeof(BMat4x4), (void *)(12 * fsize));

    // 指定 7 8 9 10 号属性每渲染 1 个实例就更新数据
    m_parent->glVertexAttribDivisor(7, 1);
    m_parent->glVertexAttribDivisor(8, 1);
    m_parent->glVertexAttribDivisor(9, 1);
    m_parent->glVertexAttribDivisor(10, 1);

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdPole::ShdPole(MainOpenGLWidget *parent) : RendererCurve(parent)
{
}

void CAGD::ShdPole::UpdateArray(AIS_Base *obj)
{
    auto pole = dynamic_cast<AIS_Pole *>(obj);
    auto hp = pole->GetPoints();
    std::vector<BPntf> points({hp[0]->Point(), hp[1]->Point()});

    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 创建纹理坐标
    int n = points.size();
    float *texCoords = new float[n];
    for (int i = 0; i < n; i++)
        texCoords[i] = 1.0 * i / (n - 1);

    // 创建空的缓冲
    m_parent->glBufferData(GL_ARRAY_BUFFER, n * (sizeof(BPntf) + sizeof(float)), NULL, GL_DYNAMIC_DRAW);

    // 分批填充
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 0, n * sizeof(BPntf), &points[0]);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, n * sizeof(BPntf), n * sizeof(float), texCoords);

    // 销毁纹理
    delete[] texCoords;

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    // vertex texture coords
    m_parent->glEnableVertexAttribArray(1);
    m_parent->glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(float), (void *)(n * sizeof(BPntf)));

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdPointLight::ShdPointLight(MainOpenGLWidget *parent) : RendererPoint(parent)
{
}

void CAGD::ShdPointLight::UpdateUniform(AIS_Base *obj)
{
    RendererPoint::UpdateUniform(obj);

    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 切换到网格着色器
    m_parent->BindShader(AIS_Type::MESH);

    // 转为字符串
    char c[255];
    itoa(obj->GetInfo().index, c, 10);
    std::string index = c;
    std::string s_position = "pointLights[" + index + "].position";
    std::string s_ambient = "pointLights[" + index + "].ambient";
    std::string s_diffuse = "pointLights[" + index + "].diffuse";
    std::string s_specular = "pointLights[" + index + "].specular";
    std::string s_constant = "pointLights[" + index + "].constant";
    std::string s_linear = "pointLights[" + index + "].linear";
    std::string s_quadratic = "pointLights[" + index + "].quadratic";

    m_parent->m_shader->setUniformValue(s_position.c_str(), CONVERT_TO_QVEC_3(obj->GetInfo().light.position));
    m_parent->m_shader->setUniformValue(s_ambient.c_str(), CONVERT_TO_QVEC_3(obj->GetInfo().light.ambient));
    m_parent->m_shader->setUniformValue(s_diffuse.c_str(), CONVERT_TO_QVEC_3(obj->GetInfo().light.diffuse));
    m_parent->m_shader->setUniformValue(s_specular.c_str(), CONVERT_TO_QVEC_3(obj->GetInfo().light.specular));
    m_parent->m_shader->setUniformValue(s_constant.c_str(), 1.0f);
    m_parent->m_shader->setUniformValue(s_linear.c_str(), 0.0022f);
    m_parent->m_shader->setUniformValue(s_quadratic.c_str(), 0.0019f);

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::ShdPointLight::UpdateArray(AIS_Base *obj)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 获得位置
    BPntf pos = obj->GetInfo().light.position;

    m_parent->glBufferData(GL_ARRAY_BUFFER, sizeof(BPntf), &pos, GL_DYNAMIC_DRAW);

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdDirLight::ShdDirLight(MainOpenGLWidget *parent) : RendererPoint(parent)
{
}

void CAGD::ShdDirLight::UpdateUniform(AIS_Base *obj)
{
    RendererPoint::UpdateUniform(obj);

    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 切换到网格着色器（这里需要生成 TopoMesh 着色器，仅仅是因为初始化时要生成一个方向光）
    m_parent->GenerateShader(AIS_Type::MESH, ":/shader/mesh.vert", ":/shader/mesh.frag", ":/shader/mesh.geom");
    m_parent->BindShader(AIS_Type::MESH);

    // 传入光照信息
    m_parent->GetShader()->setUniformValue("dirLight.direction", CONVERT_TO_QVEC_3(obj->GetInfo().light.direction));
    m_parent->GetShader()->setUniformValue("dirLight.ambient", CONVERT_TO_QVEC_3(obj->GetInfo().light.ambient));
    m_parent->GetShader()->setUniformValue("dirLight.diffuse", CONVERT_TO_QVEC_3(obj->GetInfo().light.diffuse));
    m_parent->GetShader()->setUniformValue("dirLight.specular", CONVERT_TO_QVEC_3(obj->GetInfo().light.specular));

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::ShdDirLight::UpdateArray(AIS_Base *obj)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 获得方向和位置
    BVecf vec = obj->GetInfo().light.direction.Normalized();
    BPntf origin = obj->GetInfo().light.position;

    // 创建空的缓冲
    m_parent->glBufferData(GL_ARRAY_BUFFER, 2 * sizeof(BPntf), NULL, GL_DYNAMIC_DRAW);

    // 分批填充
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(BPntf), &origin);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, sizeof(BPntf), sizeof(BPntf), &vec);

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    // vertex texture coords
    m_parent->glEnableVertexAttribArray(1);
    m_parent->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)(sizeof(BPntf)));

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdSpotLight::ShdSpotLight(MainOpenGLWidget *parent) : RendererPoint(parent)
{
}

void CAGD::ShdSpotLight::UpdateUniform(AIS_Base *obj)
{
    RendererPoint::UpdateUniform(obj);

    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 切换到网格着色器
    m_parent->BindShader(AIS_Type::MESH);

    // 传入光照信息
    char c[255];
    itoa(obj->GetInfo().index, c, 10);
    std::string index = c;
    std::string s_position = "spotLights[" + index + "].position";
    std::string s_direction = "spotLights[" + index + "].direction";
    std::string s_ambient = "spotLights[" + index + "].ambient";
    std::string s_diffuse = "spotLights[" + index + "].diffuse";
    std::string s_specular = "spotLights[" + index + "].specular";
    std::string s_constant = "spotLights[" + index + "].constant";
    std::string s_linear = "spotLights[" + index + "].linear";
    std::string s_quadratic = "spotLights[" + index + "].quadratic";
    std::string s_cutOff = "spotLights[" + index + "].cutOff";
    std::string s_outerCutOff = "spotLights[" + index + "].outerCutOff";

    m_parent->m_shader->setUniformValue(s_position.c_str(), CONVERT_TO_QVEC_3(obj->GetInfo().light.position));
    m_parent->m_shader->setUniformValue(s_direction.c_str(), CONVERT_TO_QVEC_3(obj->GetInfo().light.direction));
    m_parent->m_shader->setUniformValue(s_ambient.c_str(), CONVERT_TO_QVEC_3(obj->GetInfo().light.ambient));
    m_parent->m_shader->setUniformValue(s_diffuse.c_str(), CONVERT_TO_QVEC_3(obj->GetInfo().light.diffuse));
    m_parent->m_shader->setUniformValue(s_specular.c_str(), CONVERT_TO_QVEC_3(obj->GetInfo().light.specular));
    m_parent->m_shader->setUniformValue(s_constant.c_str(), 1.0f);
    m_parent->m_shader->setUniformValue(s_linear.c_str(), 0.0022f);
    m_parent->m_shader->setUniformValue(s_quadratic.c_str(), 0.0019f);
    m_parent->m_shader->setUniformValue(s_cutOff.c_str(), (GLfloat)cos(obj->GetInfo().light.cutOff));
    m_parent->m_shader->setUniformValue(s_outerCutOff.c_str(), (GLfloat)cos(obj->GetInfo().light.cutOff + PI / 9));

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

void CAGD::ShdSpotLight::UpdateArray(AIS_Base *obj)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();
    m_parent->BindArray(m_arrayId);

    // 获得方向和位置
    BVecf vec = obj->GetInfo().light.direction.Normalized();
    BPntf origin = obj->GetInfo().light.position;

    // 创建空的缓冲
    m_parent->glBufferData(GL_ARRAY_BUFFER, 2 * sizeof(BPntf), NULL, GL_DYNAMIC_DRAW);

    // 分批填充
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(BPntf), &origin);
    m_parent->glBufferSubData(GL_ARRAY_BUFFER, sizeof(BPntf), sizeof(BPntf), &vec);

    // vertex Positions
    m_parent->glEnableVertexAttribArray(0);
    m_parent->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)0);

    // vertex texture coords
    m_parent->glEnableVertexAttribArray(1);
    m_parent->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(BPntf), (void *)(sizeof(BPntf)));

    m_parent->UnbindArray();

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdFrame::ShdFrame(MainOpenGLWidget *parent) : RendererFrame(parent)
{
    // 进入 OpenGL 环境
    m_parent->makeCurrent();

    // 创建着色器，还带有一个绘制文字的数组
    m_parent->GenerateShader(AIS_Type::TEXT, ":/shader/text.vert", ":/shader/text.frag");
    m_parent->GenerateArray(Count());

    // 绑定着色器
    m_parent->BindShader(AIS_Type::TEXT);

    // 计算投影矩阵
    QMatrix4x4 projection;
    projection.ortho(0.0f, m_parent->width(), 0.0f, m_parent->height(), 0.1f, 1000.0f);
    m_parent->GetShader()->setUniformValue("projection", projection);
    m_parent->GetShader()->setUniformValue("color", QVector3D{1.0, 1.0, 1.0});

    // 退出 OpenGL 环境
    m_parent->doneCurrent();
}

CAGD::ShdFrame::~ShdFrame()
{
    // 销毁多出来的数组
    m_parent->DeleteArray(m_arrayId + 1);
}

void CAGD::ShdFrame::Draw(AIS_Base *obj) const
{
    // 预处理
    Prepare(obj);

    // 渲染文字
    auto frame = dynamic_cast<AIS_Frame *>(obj);
    auto size = frame->GetSize();
    m_parent->BindShader(AIS_Type::TEXT);

    // 起始位置
    int height = g_height;
    float x = size.y / 30.0, y = size.y;
    for (auto &t : frame->GetTexts())
    {
        // 换行后从头开始
        x = size.y / 30.0;
        y -= height;

        // 依次绘制字符
        for (auto c : t)
        {
            auto character = g_characters[c];

            // 获得基本数据
            GLfloat xpos = x + character.bearing.x;
            GLfloat ypos = y - (character.size.y - character.bearing.y);

            GLfloat w = character.size.x;
            GLfloat h = character.size.y;

            GLfloat vertices[6][4] = {{xpos, ypos + h, 0.0, 0.0}, {xpos, ypos, 0.0, 1.0},
                                      {xpos + w, ypos, 1.0, 1.0}, {xpos, ypos + h, 0.0, 0.0},
                                      {xpos + w, ypos, 1.0, 1.0}, {xpos + w, ypos + h, 1.0, 0.0}};

            // 传入顶点数据，绑定到第二个顶点数组上
            m_parent->BindArray(m_arrayId + 1);
            m_parent->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_DYNAMIC_DRAW);

            m_parent->glEnableVertexAttribArray(0);
            m_parent->glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void *)0);

            // 激活纹理，绑定到帧缓冲附加的纹理，绑定纹理坐标到纹理变量
            m_parent->ActiveTexture(0);
            m_parent->glBindTexture(GL_TEXTURE_2D, character.ID);
            m_parent->GetShader()->setUniformValue("tex", 0);
            m_parent->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

            m_parent->glDrawArrays(GL_TRIANGLES, 0, 6);

            m_parent->UnbindArray();

            // 更新位置到下一个字形的原点，注意单位是 1/64 像素
            x += (character.advance >> 6); // 位偏移6个单位来获取单位为像素的值 (2^6 = 64)
        }
    }

    // 完成绘制
    Done(obj);
}
